#ifndef CPPPRIMER5THCHAPTER19
#define CPPPRIMER5THCHAPTER19
#include <cstdlib>
#include <string>
#include <vector>
#include <iostream>
#include <typeinfo>
#include <functional>
#include <algorithm>

#include "../chapter7/chapter7.h"
#include "../chapter12/chapter12.h"

using std::cerr;
using std::cin;
using std::cout;
using std::endl;

// #define NDEBUG

template <typename T>
int rangeForContainer(T &a)
{
    for (auto b : a)
    {
        cout << b << ",";
    }
    cout << endl;
    return 0;
}

inline void *operator new(size_t size)
{
    if (void *mem = malloc(size))
    {
        cout << "tian's new \n";
        return mem;
    }
    else
        throw std::bad_alloc();
}

inline void operator delete(void *mem) noexcept
{
    cout << "tian's delete \n";
    free(mem);
}

// Exercises Section 19.1.1
// Exercise 19.1: Write your own operator new(size_t) function using
// malloc and use free to write the operator delete(void*) function.
int exercise19_1();

// Exercise 19.2: By default, the allocator class uses operator new to
// obtain storage and operator delete to free it. Recompile and rerun your
// StrVec programs (§ 13.5, p. 526) using your versions of the functions from
// the previous exercise.
int exercise19_2();

class AA
{
public:
    AA(){};
    inline virtual ~AA(){};
    int get() { return a; }
    int a{1};
};

class BB : public AA
{
public:
    BB() : AA(){};
    inline virtual ~BB(){};
    int get() { return b; }

    int b{2};
};

class CC : public BB
{
public:
    CC() : BB(){};
    inline virtual ~CC(){};
    int get() { return c; }

    int c{3};
};

class DD : public BB, public AA
{
public:
    DD() : BB(), AA(){};
    inline virtual ~DD(){};

    int get() { return d; }
    int d{4};
};

// Exercises Section 19.2.1
// Exercise 19.3: Given the following class hierarchy in which each class
// defines a public default constructor and virtual destructor:
// class A { /* . . . */ };
// class B : public A { /* . . . */ };
// class C : public B { /* . . . */ };
// class D : public B, public A { /* . . . */ };
// which, if any, of the following dynamic_casts fail?
// (a) A *pa = new C; B *pb = dynamic_cast< B* >(pa);
// (b) B *pb = new B; C *pc = dynamic_cast< C* >(pb);
// (c) A *pa = new D; B *pb = dynamic_cast< B* >(pa);
int exercise19_3();

// Exercise 19.4: Using the classes defined in the first exercise, rewrite the
// following code to convert the expression *pa to the type C&:
// if (C *pc = dynamic_cast< C* >(pa))
// {
//  // use C's members
// } else {
//  // use A's members
// }
int exercise19_4();

// Exercise 19.5: When should you use a dynamic_cast instead of a virtual function?
// Answer: when it is not easy to add virtual funcs to the inheritance hierarchy.
int exercise19_5();

// Exercises Section 19.2.2
// Exercise 19.6: Write an expression to dynamically cast a pointer to a
// Query_base to a pointer to an AndQuery (§ 15.9.1, p. 636). Test the cast
// by using objects of AndQuery and of another query type. Print a statement
// indicating whether the cast works and be sure that the output matches your
// expectations.
// Answer: not inerested.
int exercise19_6();

// Exercise 19.7: Write the same cast, but cast a Query_base object to a
// reference to AndQuery. Repeat the test to ensure that your cast works
// correctly.
// Answer: not inerested.
int exercise19_7();

// Exercise 19.8: Write a typeid expression to see whether two
// Query_base pointers point to the same type. Now check whether that type
// is an AndQuery.
// Answer: not inerested.
int exercise19_8();

// Exercises Section 19.2.4
// Exercise 19.9: Write a program similar to the last one in this section to
// print the names your compiler uses for common type names. If your compiler
// gives output similar to ours, write a function that will translate those strings
// to more human-friendly form.
// Answer: not inerested.
int exercise19_9();

// Exercise 19.10: Given the following class hierarchy in which each class
// defines a public default constructor and virtual destructor, which type name
// do the following statements print?
// class A
// { /* . . . */};
// class B : public A
// { /* . . . */};
// class C : public B
// { /* . . . */};
// (a) A *pa = new C;
//     cout << typeid(pa).name() << endl;
// (b) C cobj;
//     A &ra = cobj;
//     cout << typeid(&ra).name() << endl;
// (c) B *px = new B;
//     A &ra = *px;
//     cout << typeid(ra).name() << endl;
int exercise19_10();

// Exercises Section 19.4.1
// Exercise 19.11: What is the difference between an ordinary data pointer
// and a pointer to a data member?
// Answer: ordinary data pointer is pointing to a certain obj when it is inited, but
// that pointer does not yet point to any data. It identifies a specific member but not the
// object that contains that member. We supply the object when we dereference the
// pointer to member.
int exercise19_11();

// Exercise 19.12: Define a pointer to member that can point to the cursor
// member of class Screen. Fetch the value of Screen::cursor through that pointer.
int exercise19_12();

// Exercise 19.13: Define the type that can represent a pointer to the bookNo
// member of the Sales_data class.
int exercise19_13();

// Exercises Section 19.4.2
// Exercise 19.14: Is the following code legal? If so, what does it do? If not, why?
// auto pmf = &Screen::get_cursor; // pmf is init to a member func pointer that point to Screen::get_cursor;
// pmf = &Screen::get; // pmf is assigned to point to Screen::get, which is legal,
// because get_cursor and get both dont have parameters and both are const.
int exercise19_14();

// Exercise 19.15: What is the difference between an ordinary function pointer
// and a pointer to a member function?
// Answer: (1) First of all, not like ordinary func pointer, there is no auto convert from funcname to a pointer to a member function.
int exercise19_15();

// Exercise 19.16: Write a type alias that is a synonym for a pointer that can
// point to the avg_price member of Sales_data.
int exercise19_16();

// Exercise 19.17: Define a type alias for each distinct Screen member function type.
// Answer: meaningless
int exercise19_17();

// Exercises Section 19.4.3
// Exercise 19.18: Write a function that uses count_if to count how many
// empty strings there are in a given vector.
int exercise19_18();

// Exercise 19.19: Write a function that takes a vector<Sales_data> and
// finds the first element whose average price is greater than some given
// amount.
int exercise19_19();

// Exercises Section 19.5
// Exercise 19.20: Nest your QueryResult class inside TextQuery and
// rerun the programs you wrote to use TextQuery in § 12.3.2 (p. 490).
int exercise19_20();

class Token
{
    friend std::ostream &operator<<(std::ostream &, const Token &);

public:
    Token() : tok(INT), ival(0) {}
    Token(const Token &t) : tok(t.tok) { copyUnion(t); }
    Token &operator=(const Token &);
    Token(Token &&t) : tok(t.tok)
    {
        cout << "using move constructor\n";
        moveUnion(std::move(t));
    };
    Token &operator=(Token &&);

    ~Token()
    {
        if (tok == STR)
            sval.~string();
        if (tok == SDATA)
            sdval.~Sales_data();
    }
    Token &operator=(const std::string &);
    Token &operator=(char);
    Token &operator=(int);
    Token &operator=(double);
    Token &operator=(const Sales_data &);

private:
    enum
    {
        INT,
        CHAR,
        DBL,
        STR,
        SDATA
    } tok; // discriminant
    union
    {
        char cval;
        int ival;
        double dval;
        std::string sval;
        Sales_data sdval;
    };
    void copyUnion(const Token &);
    void moveUnion(Token &&);
};

inline std::ostream &operator<<(std::ostream &os, const Token &t)
{
    switch (t.tok)
    {
    case Token::INT:
        return os << t.ival;
    case Token::CHAR:
        return os << t.cval;
    case Token::DBL:
        return os << t.dval;
    case Token::STR:
        return os << t.sval;
    case Token::SDATA:
        return os << t.sdval.isbn();
    }
}

// Exercises Section 19.6
// Exercise 19.21: Write your own version of the Token class.
int exercise19_21();

// Exercise 19.22: Add a member of type Sales_data to your Token class.
int exercise19_22();

// Exercise 19.23: Add a move constructor and move assignment to Token.
int exercise19_23();

// Exercise 19.24: Explain what happens if we assign a Token object to itself.
int exercise19_24();

// Exercise 19.25: Write assignment operators that take values of each type in
// the union.
int exercise19_25();

// Exercises Section 19.8.3
// Exercise 19.26: Explain these declarations and indicate whether they are
// legal:
// extern "C" int compute(int *, int);
// extern "C" double compute(double *, double);
// Answer: both declarations are legally allowed in C++ as individual declarations,
// but using them together in a way that requires C linkage can lead to linker errors due to name conflicts.
// C does not support function overloading, say: two compute funs with different parameters.
int exercise19_26();

#endif